package utils

import (
	"fmt"
	"os"
	"path"
	"runtime"
	"sync"
	"time"

	"github.com/wzshiming/ctc"
)

// LogConfig 日志设置
type LogConfig struct {
	Dir        string `json:"dir"`
	FileLength int64  `json:"filelength"`
	FileLevel  int    `json:"filelevel"`
}

const (
	// LogLevelDebug 调试日志
	LogLevelDebug = iota
	// LogLevelInfo 信息日志
	LogLevelInfo
	// LogLevelWarning 警告日志
	LogLevelWarning
	// LogLevelError 错误日志
	LogLevelError
	// LogLevelCritic 评判日志
	LogLevelCritic
)

const (
	winBlack = iota
	winBlue
	winGreen
	winCyan
	winRed
	winPurple
	winYellow
	winLightGray
	winGray
	winLightBlue
	winLightGreen
	winLightCyan
	winLightRed
	winLightPurple
	winLightYellow
	winWhite
)

// StLogger 日志对象
type StLogger struct {
	mFileDir          string
	mFileHandle       *os.File
	mCurDate          time.Time
	mCurPath          string
	mCurFolder        string
	mStackDepth       int
	mMaxLogFileLength int64
	mWriteFileLevel   int
	mMu               sync.Mutex
}

var isWin bool

// NewStLogger 实例化logger
func NewStLogger(dir string, fileLength int64, fileLevel int) *StLogger {
	logger := &StLogger{
		mFileDir:          "",
		mCurPath:          "",
		mCurFolder:        "",
		mFileHandle:       nil,
		mStackDepth:       3,
		mWriteFileLevel:   fileLevel,
		mMaxLogFileLength: 20971520,
	}

	if !IsDir(dir) {
		err := os.MkdirAll(dir, os.ModePerm)
		if err != nil {
			panic("logger create dir failed : " + err.Error())
		}
	}
	logger.mFileDir = dir

	if fileLength > 0 {
		logger.mMaxLogFileLength = fileLength
	}

	if runtime.GOOS == "windows" {
		isWin = true
	}

	return logger
}

func (s *StLogger) fileHandle() *os.File {
	now := time.Now()
	fileDir := fmt.Sprintf("%s/%d%d%d/", s.mFileDir, now.Year(), now.Month(), now.Day())
	if !IsDir(fileDir) {
		err := os.MkdirAll(fileDir, os.ModePerm)
		if err != nil {
			fmt.Println("logger create dir failed : " + err.Error())
			return nil
		}
	}
	if s.mCurFolder != fileDir {
		if s.mFileHandle != nil {
			s.mFileHandle.Close()
			s.mFileHandle = nil
		}
		s.mCurFolder = fileDir
		s.mCurPath = fmt.Sprintf("%s%s%s", s.mCurFolder, "log", ".log")
	}
	_, size := GetFileByteSize(s.mCurPath)
	if size > s.mMaxLogFileLength {
		s.removeFile()
	}
	if s.mFileHandle == nil {
		fileHandle, err := os.OpenFile(s.mCurPath, os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
		if err != nil {
			fmt.Println("log file create failed : ", err.Error())
			return nil
		}
		s.mFileHandle = fileHandle

	}

	return s.mFileHandle
}

func (s *StLogger) removeFile() {
	now := time.Now()

	if s.mFileHandle != nil {
		s.mFileHandle.Close()
		s.mFileHandle = nil
	}
	count, _, err := GetDirFilesCount(s.mCurFolder, false)
	if err == nil {
		newName := fmt.Sprintf("%s%s_%d_%d%d%d%s", s.mCurFolder, "log", count, now.Year(), now.Month(), now.Day(), ".log")
		os.Rename(s.mCurPath, newName)
	}
}

// Msg 打印日志并写入文件 https://github.com/fang2329/logger/tree/master/common_log
func (s *StLogger) Msg(level int, logMsg string, preFlag string) {

	logMsg = Trim(logMsg)

	flag := getLoggerLevel(level)

	caller := ""

	_, file, line, ok := runtime.Caller(s.mStackDepth)
	if ok == false {
		fmt.Println("caller get failed!")
	}
	name := path.Base(file)
	caller = fmt.Sprintf("[%s:%d] ", name, line)

	time := time.Now().Format("2006-01-02 15:04:05.000")
	if len(preFlag) > 0 {
		preFlag += " "
	}
	msg := fmt.Sprintf("%s%s %s : %s %s", preFlag, time, caller, flag, logMsg)

	if level >= s.mWriteFileLevel {
		s.mMu.Lock()
		handle := s.fileHandle()
		if handle != nil {
			Write(s.mFileHandle, msg+"\n")
		}
		s.mMu.Unlock()
	}

	// if isWin {
	// 	print(msg + "\n")

	// } else {

	fmt.Println(preFlag, time, caller, getPrintType(level), flag, ctc.Reset, logMsg)
	// }
}

func getPrintType(level int) ctc.Color {

	switch level {
	case LogLevelDebug:
		return ctc.ForegroundBright
	case LogLevelInfo:
		return ctc.ForegroundGreen
	case LogLevelWarning:
		return ctc.ForegroundYellow
	case LogLevelError:
		return ctc.ForegroundRed
	case LogLevelCritic:
		return ctc.ForegroundCyan
	default:
		return ctc.ForegroundWhite
	}
}

func getLoggerLevel(level int) string {
	switch level {
	case LogLevelDebug:
		return "[DEBUG]"
	case LogLevelInfo:
		return "[INFO]"
	case LogLevelWarning:
		return "[WARNING]"
	case LogLevelError:
		return "[ERROR]"
	case LogLevelCritic:
		return "[CRITIC]"
	default:
		return ""
	}
}

var logger *StLogger

// InitLogger 初始化日志对象
func InitLogger(dir string, fileLength int64, fileLevel int) {
	logger = NewStLogger(dir, fileLength, fileLevel)
}

// Debug 输出调试日志
func Debug(format string, args ...interface{}) {
	msg(LogLevelDebug, fmt.Sprintf(format, args...))
}

// Info 输出信息日志
func Info(format string, args ...interface{}) {
	msg(LogLevelInfo, fmt.Sprintf(format, args...))
}

// Warning 输出警告日志
func Warning(format string, args ...interface{}) {
	msg(LogLevelWarning, fmt.Sprintf(format, args...))
}

// Error 输出错误日志，并返回一个error对象
func Error(format string, args ...interface{}) error {
	err := fmt.Errorf(fmt.Sprintf(format, args...))
	msg(LogLevelError, err.Error())
	return err
}

// Critic 输出评判日志
func Critic(format string, args ...interface{}) {
	msg(LogLevelCritic, fmt.Sprintf(format, args...))
}

func msg(level int, msg string) {
	if nil != logger {
		logger.Msg(level, msg, "")
	} else {
		fmt.Println(msg)
	}
}
